/*
    This file is part of Raptor.

    Raptor is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Raptor is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Raptor.  If not, see <http://www.gnu.org/licenses/>.

 */

#include "../include/raptor.h"
#include "../include/importWizard.h"
#include "../include/captchaWizard.h"
#include "../include/clipboardDialog.h"
#include "../include/xmlFileLoader.h"
#include "../include/xmlUrlContainer.h"
#include "../include/xmlUpdater.h"
#include "../include/container.h"

#include <QInputDialog>
#include <QTimer>
#include <QModelIndexList>
#include <QTime>
#include <QFile>
#include <QSettings>
#include <QStandardItemModel>
#include <QProgressBar>
#include <QItemDelegate>
#include <QAction>
#include <QClipboard>
#include <QProcess>

class ItemDelegate: public QItemDelegate
{
public:
    ItemDelegate(QObject* parent = 0): QItemDelegate(parent)
    {

    }

    void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
    {
        if(index.parent().row() != -1 && index.column() == FDownloadModel::CD_PROGRESS)
        {
            QStyleOptionProgressBarV2 opt;
            opt.rect = option.rect;
            opt.minimum = 0;
            opt.maximum = 100;
            opt.progress = index.data(0).toInt();
            opt.text = QString("%1 %").arg(opt.progress);
            opt.textVisible = true;
            opt.textAlignment = Qt::AlignHCenter;

            QApplication::style()->drawControl(QStyle::CE_ProgressBar, &opt, painter, 0);
        } else
        {
            QItemDelegate::paint(painter, option, index);
        }
    }
};

Raptor::Raptor(S_PROXY _proxy, QString const &folderRaptor, QString const &folderDownload)
{
    ui.setupUi(this);

    setProxy(_proxy);

    maxDownloads = 1;
    urlContainerIsOpen = false;
    silentAddDl = false;
    dontSaveDl = false;
    ready = false;

    waitingDls.clear();

    folders.setDirs(folderRaptor, folderDownload, "captcha", "hoster", "urlContainer");

    urlContainer.setCaptchaDir(folders.captcha.absolutePath());
    urlContainer.setXmlDir(folders.container.absolutePath());

    QCoreApplication::setOrganizationName("raptor-loader");
    QCoreApplication::setOrganizationDomain("raptor-loader.org");
    QCoreApplication::setApplicationName("Raptor");
    QCoreApplication::setApplicationVersion("0.13");

    QApplication::setQuitOnLastWindowClosed(false);

    //tray icon erstellen
    trayIcon = new QSystemTrayIcon;
    trayIcon->setIcon(QPixmap(":/toolbar/raptor_v2.svg"));
    connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slot_systemTray_activated(QSystemTrayIcon::ActivationReason)));

    trayMenu = new QMenu();

    trayActionShow = new QAction(QPixmap(":/toolbar/play.svg"), tr("Show"), this);
    connect(trayActionShow, SIGNAL(triggered()), this, SLOT(slot_appShow()));
    trayMenu->addAction(trayActionShow);

    trayActionHide = new QAction(QPixmap(":/toolbar/pause.svg"), tr("Hide"), this);
    connect(trayActionHide, SIGNAL(triggered()), this, SLOT(slot_appHide()));
    trayMenu->addAction(trayActionHide);

    trayMenu->addSeparator();

    trayActionQuit = new QAction(QPixmap(":/toolbar/raptor_v2.svg"), tr("Quit"), this);
    connect(trayActionQuit, SIGNAL(triggered()), this, SLOT(slot_performClose()));
    trayMenu->addAction(trayActionQuit);

    trayIcon->setContextMenu(trayMenu);
    trayIcon->setVisible(true);
    //<-- tray icon

    //rechts klick menu fuer downloads:
    downloadRightClickMenu = new QMenu();
    downloadRightClickMenu->addAction(ui.actionAddLink);
    downloadRightClickMenu->addAction(ui.actionAddFile);
    downloadRightClickMenu->addSeparator();
    downloadRightClickMenu->addAction(ui.actionAddFolder);
    downloadRightClickMenu->addSeparator();
    downloadRightClickMenu->addAction(ui.actionStart);
    downloadRightClickMenu->addAction(ui.actionPause);
    downloadRightClickMenu->addAction(ui.actionDelete);
    downloadRightClickMenu->addSeparator();
    downloadRightClickMenu->addAction(ui.actionRemoveFinished);
    downloadRightClickMenu->addSeparator();
    downloadRightClickMenu->addAction(ui.actionMoveUp);
    downloadRightClickMenu->addAction(ui.actionMoveDown);
    //

    //rechts klick menu fuer finished
    historyRightClickMenu = new QMenu();
    historyRightClickMenu->addAction(ui.actionDelete);
    //

    //programm ende connecten
    connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(slot_app_aboutToQuit()));
    connect(ui.actionExit, SIGNAL(triggered()), this, SLOT(slot_performClose()));
    //

    fileLoader.clear();

    //timer um gui zu refreshen
    timerFileList = new QTimer(this);
    connect(timerFileList, SIGNAL(timeout()), this, SLOT(slot_timerFileList_timeout()));
    timerFileList->start(500);

    connect(ui.btn_openFolder, SIGNAL(clicked()), this, SLOT(slot_openFolder()));

    //treeViewModels aufsetzen
    modelHistory = new QStandardItemModel(0, 4);
    modelHistory->setHeaderData(0, Qt::Horizontal, tr("Filename"));
    modelHistory->setHeaderData(1, Qt::Horizontal, tr("Url"));
    modelHistory->setHeaderData(2, Qt::Horizontal, tr("Size"));
    modelHistory->setHeaderData(3, Qt::Horizontal, tr("Size Bytes"));

    ui.treeViewHistory->setModel(modelHistory);
    ui.treeViewHistory->setAlternatingRowColors(true);
    ui.treeViewHistory->setUniformRowHeights(true);
    ui.treeViewHistory->setIconSize(QSize(24, 24));

    ui.treeViewHistory->setColumnHidden(3, true);

    modelDownloads = new FDownloadModel();
    ui.treeViewDownloads->setModel(modelDownloads);
    ui.treeViewDownloads->setColumnHidden(FDownloadModel::CD_HIDDEN_DLID, true);
    ui.treeViewDownloads->setColumnHidden(FDownloadModel::CD_HIDDEN_STATE, true);
    ui.treeViewDownloads->setColumnHidden(FDownloadModel::CD_HIDDEN_ID, true);
    ui.treeViewDownloads->setColumnHidden(FDownloadModel::CD_LINK, true);

    ui.treeViewDownloads->setItemDelegateForColumn(FDownloadModel::CD_PROGRESS, new ItemDelegate(ui.treeViewDownloads));
    ui.treeViewDownloads->setAlternatingRowColors(true);
    ui.treeViewDownloads->setUniformRowHeights(true);
    ui.treeViewDownloads->setIconSize(QSize(24, 24));

    ui.treeViewDownloads->setContextMenuPolicy(Qt::CustomContextMenu);
    ui.treeViewHistory->setContextMenuPolicy(Qt::CustomContextMenu);
    //

    //updaten
    xmlUpdater xmlUp;

    xmlUp.updateRaptor(this);

    xmlUp.setHosterPath(folders.hoster.path());
    xmlUp.updateHoster();
    
    xmlUp.setContainerPath(folders.container.path());
    xmlUp.updateContainer();
    //

    //hoster laden
    loadHosterXml();
    //downloads laden
    loadDls();
    ready = true;

    //add waiting dls
    QMap<QString, QString>::const_iterator it = waitingDls.constBegin();
    while(it != waitingDls.constEnd())
    {
        addUrl(it.value(), it.key());
        ++it;
    }
    waitingDls.clear();

    ui.dockWidget->setMaximumHeight(200);

    //for(int i=0; i<FDownloadModel::CD_HIDDEN_ID; ++i)
       // ui.treeViewDownloads->resizeColumnToContents(i);

    //clipboard abfrage
    clipboard = QApplication::clipboard();
    connect(clipboard, SIGNAL(dataChanged()), this, SLOT(slot_clipboard_dataChanged()));
}

Raptor::~Raptor()
{
}

//private


void Raptor::setProxy(S_PROXY const &_proxy)
{
    proxy = _proxy;
    setProxy();
}

void Raptor::setProxy()
{
    QNetworkProxy tmpProxy(proxy.type, proxy.host, proxy.port, proxy.user, proxy.pass);

    QNetworkProxy::setApplicationProxy(tmpProxy);

    //fileloader
    QMap<int, QPointer<xmlFileLoader> >::const_iterator i = fileLoader.constBegin();
    while(i != fileLoader.constEnd())
    {
            i.value()->setProxy(tmpProxy);
            ++i;
    }

    //urlc
    urlContainer.setProxy(tmpProxy);
}

void Raptor::addInfo(QString str)
{
	ui.textEditGlobalLog->append(QTime::currentTime().toString("hh:mm:ss") + ": " + str);
}

void Raptor::modifyItems(const modifyAction &action)
{
	QItemSelectionModel *selections = ui.treeViewDownloads->selectionModel();
	QModelIndexList selected = selections->selectedRows();

	for(int p=0; p<selected.count(); ++p)
	{
		if(selected.at(p).parent().row() == -1) //ist hoster
		{
			QStandardItem * hoster = modelDownloads->item(selected.at(p).row());

			if(hoster->hasChildren())
			{
				for(int i=0; i<selected.count(); ++i)
				{
					switch(action)
					{
						case ACTION_START:
							startFolder(hoster->child(i));
							break;
						case ACTION_PAUSE:
							pauseFolder(hoster->child(i));
							break;
					}
				}
			}
		} else
		{
			if(selected.at(p).parent().parent().row() == -1) //ist folder
			{
				QStandardItem * hoster = modelDownloads->item(selected.at(p).parent().row());
				QStandardItem * folder = hoster->child(selected.at(p).row());

				switch(action)
				{
					case ACTION_START:
						startFolder(folder);
						break;
					case ACTION_PAUSE:
						pauseFolder(folder);
						break;
				}

			} else // ist download
			{
				QStandardItem * hoster = modelDownloads->item(selected.at(p).parent().parent().row());
				QStandardItem * folder = hoster->child(selected.at(p).parent().row());

				switch(action)
				{
					case ACTION_START:
						startDownload(folder, selected.at(p).row());
						break;
					case ACTION_PAUSE:
						pauseDownload(folder, selected.at(p).row());
						break;
				}
			}
		}
	}
}

void Raptor::startFolder(QStandardItem * folder)
{
	if(folder->hasChildren())
	{
		for(int i=0; i<folder->rowCount(); ++i)
		{
			startDownload(folder, i);
		}
	}
}

void Raptor::startDownload(QStandardItem * folder, int row)
{
	int tmpId = folder->child(row, FDownloadModel::CD_HIDDEN_DLID)->text().toInt(); //downloader id
	int tmpState = folder->child(row, FDownloadModel::CD_HIDDEN_STATE)->text().toInt(); //state
	int tmpLogId = folder->child(row, FDownloadModel::CD_HIDDEN_ID)->text().toInt(); //download id in liste

	if(tmpId >= 0)
	{
		writeFileLog(tmpLogId, tr("Download already running !!"));
	} else
	{
		if(tmpState != xmlFileLoader::STATE_FINISHED)
		{
                        tmpId = startFileLoader(folder->child(row, FDownloadModel::CD_LINK)->text(),
                                                folders.download.absolutePath() + QDir::separator() + folder->parent()->child(folder->row(), FDownloadModel::CD_FILENAME)->text(),
                                                folder->child(row, FDownloadModel::CD_FILENAME)->text(),
                                                tmpLogId);

			if(tmpId >= 0)
			{
				folder->child(row, FDownloadModel::CD_HIDDEN_DLID)->setText(QString("%1").arg(tmpId));
				folder->child(row, FDownloadModel::CD_HIDDEN_STATE)->setText(QString("%1").arg(xmlFileLoader::STATE_RUNNING));
			} else
			{
				folder->child(row, FDownloadModel::CD_HIDDEN_STATE)->setText(QString("%1").arg(xmlFileLoader::STATE_STALLED));
			}

		} else
		{
			writeFileLog(tmpLogId, tr("Download already finished !!"));
		}
	}
}

void Raptor::pauseFolder(QStandardItem * folder)
{
	if(folder->hasChildren())
	{
		for(int i=0; i<folder->rowCount(); ++i)
		{
			pauseDownload(folder, i);
		}
	}
}

void Raptor::pauseDownload(QStandardItem * folder, int row)
{
	int tmpId = folder->child(row, FDownloadModel::CD_HIDDEN_DLID)->text().toInt();
	int tmpState = folder->child(row, FDownloadModel::CD_HIDDEN_STATE)->text().toInt();
	int tmpLogId = folder->child(row, FDownloadModel::CD_HIDDEN_ID)->text().toInt();

	if(fileLoader.contains(tmpId))
	{
		if(fileLoader.value(tmpId)->state() != xmlFileLoader::STATE_STOPPED)
		{
			deleteFileLoader(tmpId);
		}
	}
	folder->child(row, FDownloadModel::CD_HIDDEN_DLID)->setText("-1");

	if(tmpState != xmlFileLoader::STATE_FINISHED)
	{
		if(tmpState != xmlFileLoader::STATE_STOPPED) writeFileLog(tmpLogId, tr("Download paused."));
		folder->child(row, FDownloadModel::CD_HIDDEN_STATE)->setText(QString("%1").arg(xmlFileLoader::STATE_STOPPED));
	} else
	{
		writeFileLog(tmpLogId, tr("Download already finished !!"));
	}
}

void Raptor::deleteDownload(QStandardItem * folder, int row)
{
	if(folder->rowCount() > row)
	{
		int tmpId = folder->child(row, FDownloadModel::CD_HIDDEN_DLID)->text().toInt();
		int tmpLogId = folder->child(row, FDownloadModel::CD_HIDDEN_ID)->text().toInt();

		if(tmpId >= 0) deleteFileLoader(tmpId); //wenn download laeuft, stoppen

		if(tmpLogId < logStrings.count()) logStrings.at(tmpLogId)->clear();

		folder->removeRow(row); //entferne download
		//if(!modelDownloads->item(i)->child(r.value())->hasChildren()) modelDownloads->item(i)->removeRow(r.value()); //wenn alle links aus einem ordner geloescht, dann loesche auch ordner

		dlChanged();
	}
}

void Raptor::setSize(const int &logId, const uint &downloaded, const uint &size)
{

	for(int p=0; p<modelDownloads->rowCount(); ++p)
	{
		QStandardItem *hoster = modelDownloads->item(p);

		if(hoster->hasChildren())
		{
			for(int i=0; i<hoster->rowCount(); ++i)
			{
				QStandardItem *folder = hoster->child(i);

				if(folder->hasChildren())
				{
					for(int o=0; o<folder->rowCount(); ++o)
					{
						int tmpLogId = folder->child(o, FDownloadModel::CD_HIDDEN_ID)->text().toInt();

						if(tmpLogId == logId)
						{
							folder->child(o, FDownloadModel::CD_SIZE)->setText(getSizeString(downloaded, size));
							return;
                                                }
					}
				}
			}
		}
	}
}

void Raptor::writeFileLog(const int &id, const QString &text)
{
	if(id < 0)
	{
		addInfo(text);
		return;
	}

	QString logText = QTime::currentTime().toString("hh:mm:ss") + ": " + text;

	if(activeLog == id) ui.textEditLog->append(logText); //valgrind meckert
	if(logStrings.count() >= id) logStrings.at(id)->append(logText);
}

void Raptor::addFinishedDownload(const QString &name, const QString &link, const uint &size)
{
	QList<QStandardItem *> listItem;

	//name
	QStandardItem *item = new QStandardItem(name);
	item->setIcon(getPixmapByState(xmlFileLoader::STATE_HISTORY));
	listItem.append(item);

	//info
	QStandardItem *itemText = new QStandardItem(link);
	listItem.append(itemText);

	itemText = new QStandardItem(getSizeString(size));
	listItem.append(itemText);

	itemText = new QStandardItem(QString("%1").arg(size));
	listItem.append(itemText);

	modelHistory->insertRow(0, listItem);

	dlChanged();
}

void Raptor::loadHosterXml()
{
	hosterList.clear();

	QSettings settings("raptor-loader", "Raptor");

	QDir tmpDir = folders.hoster;
	if(tmpDir.exists())
	{
		//QDir tmpDir = QDir::current().path() + "/hoster/";

		tmpDir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);

		QFileInfoList list = tmpDir.entryInfoList();

		for(int i=0; i<list.size(); ++i)
		{
			QFileInfo fileInfo = list.at(i);

			if(fileInfo.fileName().right(3).toLower() == "xml")
			{
				QFile file(tmpDir.absolutePath() + QDir::separator() + fileInfo.fileName());
				QDomDocument domHoster = QDomDocument("hoster");

				if(file.open(QIODevice::ReadOnly))
				{
					if(domHoster.setContent(&file))
					{
                                                bool allowOtherHostnames = false;
						QString tmpHoster = "";
                                                QString tmpRegExp = "^$";
                                                QString tmpRegExp2 = "^$";
						QString tmpFreeMaxDl = "0";
						QString tmpPremiumMaxDl = "0";

                                                if(domHoster.childNodes().at(0).attributes().contains("host"))
                                                {
                                                        tmpHoster = domHoster.childNodes().at(0).attributes().namedItem("host").nodeValue();
                                                }

                                                if(domHoster.childNodes().at(0).attributes().contains("allowOtherHostnames"))
                                                {
                                                    allowOtherHostnames = domHoster.childNodes().at(0).attributes().namedItem("allowOtherHostnames").nodeValue() == "1" ? true: false;
                                                }

						QDomNodeList tmpNodeList = domHoster.elementsByTagName("url_regexp");
						if(!tmpNodeList.isEmpty())
						{
                                                    if(tmpNodeList.at(0).attributes().contains("host"))
                                                    {
                                                            tmpRegExp = tmpNodeList.at(0).attributes().namedItem("host").nodeValue();
                                                    }
                                                    if(tmpNodeList.at(0).attributes().contains("link"))
                                                    {
                                                            tmpRegExp2 = tmpNodeList.at(0).attributes().namedItem("link").nodeValue();
                                                    }
						}

						if(domHoster.elementsByTagName("free").at(0).attributes().contains("max_downloads"))
						{
							tmpFreeMaxDl = domHoster.elementsByTagName("free").at(0).attributes().namedItem("max_downloads").nodeValue();
						}

						if(domHoster.elementsByTagName("premium").at(0).attributes().contains("max_downloads"))
						{
							tmpPremiumMaxDl = domHoster.elementsByTagName("premium").at(0).attributes().namedItem("max_downloads").nodeValue();
						}

						xmlFileLoader::E_MODE tmpMode = xmlFileLoader::MODE_FREE;

						bool tmpBool = true;
						QDomNamedNodeMap tmpAttrList = domHoster.elementsByTagName("premium").at(0).firstChildElement("settings").attributes();
						for(int o=0; o<tmpAttrList.size(); ++o)
						{
							if(!settings.contains("hoster/" + tmpHoster + "/settings/" + tmpAttrList.item(o).nodeName()))
							{
								tmpBool = false;
								break;
							}
						}

						if(tmpBool)
						{
							tmpMode = xmlFileLoader::MODE_PREMIUM;
							addInfo(tr("found Premium Account for hoster: ") + tmpHoster);
						} else
						{
							addInfo(tr("use Free Account for hoster: ") + tmpHoster);
						}

						QSettings settings("raptor-loader", "Raptor");

						int tmpMaxDownloads = settings.value("hoster/" + tmpHoster + "/maxDownloads", 0).toInt();

                                                //qDebug() << "hoster" << file.fileName() << tmpHoster << tmpRegExp;
                                                hosterList.append(new S_HOSTER(file.fileName(), tmpHoster, QRegExp(tmpRegExp), QRegExp(tmpRegExp2), tmpMaxDownloads, tmpFreeMaxDl.toInt(), tmpPremiumMaxDl.toInt(), tmpMode, allowOtherHostnames));

						modelDownloads->createHoster(tmpHoster);
					} else
					{
					    qDebug() << "Error in xml file: " << file.fileName();
					}
					file.close();
				}
			}
		}
	}

	reloadCurrentDlCount();
}

void Raptor::reloadCurrentDlCount()
{
	QMap<int, QPointer<xmlFileLoader> >::const_iterator i = fileLoader.constBegin();
	while(i != fileLoader.constEnd())
	{
		int tmpId = getHosterIdByUrl(i.value()->link());

		if(tmpId >= 0)
		{
			if(i.value()->mode() == xmlFileLoader::MODE_FREE)
				hosterList.at(tmpId)->free.downloads++;
			else if(i.value()->mode() == xmlFileLoader::MODE_PREMIUM)
				hosterList.at(tmpId)->premium.downloads++;
		}

		++i;
	}
}

bool Raptor::getLoaderInfos(const int &id, S_INFOS &infos)
{
	if(fileLoader.contains(id))
	{
		infos.downloadStart = fileLoader.value(id)->downloadStart();
		infos.downloaded = fileLoader.value(id)->downloaded();
		infos.fileSize = fileLoader.value(id)->fileSize();
		infos.progress = fileLoader.value(id)->progress();
		infos.speed = fileLoader.value(id)->speed();
		infos.state = fileLoader.value(id)->state();
		infos.timeLeft = fileLoader.value(id)->timeLeft();

		return true;
	} else
	{
		return false;
	}
}

void Raptor::deleteFileLoader(const int &id)
{
	if(!fileLoader.contains(id)) return;

	int tmpHosterId = getHosterIdByUrl(fileLoader.value(id)->link());

	if(tmpHosterId < 0 || tmpHosterId >= hosterList.size()) return;

	//dec downloads
	switch(fileLoader.value(id)->mode())
	{
		case xmlFileLoader::MODE_FREE:

			hosterList.at(tmpHosterId)->free.downloads--;
			if(hosterList.at(tmpHosterId)->free.downloads < 0) hosterList.at(tmpHosterId)->free.downloads = 0;
			break;

		case xmlFileLoader::MODE_PREMIUM:

			hosterList.at(tmpHosterId)->premium.downloads--;
			if(hosterList.at(tmpHosterId)->premium.downloads < 0) hosterList.at(tmpHosterId)->premium.downloads = 0;
			break;

		case xmlFileLoader::MODE_LOGIN:

			break;

		case xmlFileLoader::MODE_GET_SIZE:

			break;
	}


	//wenn schon gesaugt wurde, datei loeschen
	if(fileLoader.value(id)->downloadFile())
	{
	    if(fileLoader.value(id)->downloadFile()->isOpen())
	    {
		fileLoader.value(id)->downloadFile()->close();
		fileLoader.value(id)->downloadFile()->remove();
	    }
	}

	//funktioniert das hier richtig ??
	disconnect(fileLoader.value(id), 0, this, 0);

	fileLoader.value(id)->deleteLater();
	fileLoader.remove(id);
}

int Raptor::startLoginFileLoader(const QString &hoster, const QString &user, const QString &pass)
{
	int tmpHosterId = getHosterIdByUrl("http://" + hoster);

	if(tmpHosterId < 0 || tmpHosterId >= hosterList.size()) return -1;

	int id = getNewFileLoader();

	if(fileLoader.contains(id))
	{
		fileLoader.value(id)->loadXml(hosterList.at(tmpHosterId)->fileName);
		fileLoader.value(id)->setId(id);
		fileLoader.value(id)->setLogId(-1);

		if(fileLoader.value(id)->setLink(QUrl("http://" + hoster)))
		{
			connect(fileLoader.value(id), SIGNAL(loginFinished(const int, const bool)), this, SLOT(slot_xmlFileLoader_loginFinished(const int, const bool)));
			connect(fileLoader.value(id), SIGNAL(downloadFinished(const int &, const bool &)), this, SLOT(slot_xmlFileLoader_downloadFinished(const int &, const bool &)));

			fileLoader.value(id)->login(user, pass);

			return id;
		} else
		{
			writeFileLog(-1, tr("Login Link not valid."));
			deleteFileLoader(id);
			return -1;
		}
	}

	return -1;
}

int Raptor::startGetSizeFileLoader(const QString &link, const int &logId)
{
	int tmpHosterId = getHosterIdByUrl(link);

	if(tmpHosterId < 0 || tmpHosterId >= hosterList.size()) return -1;

	int id = getNewFileLoader();

	if(fileLoader.contains(id))
	{
		fileLoader.value(id)->loadXml(hosterList.at(tmpHosterId)->fileName);
		fileLoader.value(id)->setId(id);
		fileLoader.value(id)->setLogId(logId);

		if(fileLoader.value(id)->setLink(QUrl(link)))
		{
			connect(fileLoader.value(id), SIGNAL(getSizeFinished(const int, const bool)), this, SLOT(slot_xmlFileLoader_getSizeFinished(const int, const bool)));
			connect(fileLoader.value(id), SIGNAL(downloadFinished(const int &, const bool &)), this, SLOT(slot_xmlFileLoader_downloadFinished(const int &, const bool &)));

			fileLoader.value(id)->getSize();

			return id;
		} else
		{
			writeFileLog(-1, tr("Login Link not valid."));
			deleteFileLoader(id);
			return -1;
		}
	}

	return -1;
}

int Raptor::startFileLoader(const QString &link, const QString &folder, const QString &file, const int &logId)
{
	//gesamt download limit, 0 ^= kein limit
	if(maxDownloads > 0 && getDownloadCount() >= maxDownloads)
	{
		addInfo(tr("Maximum number of simultaneous downloads reached"));
		return -1;
	}

	int tmpHosterId = getHosterIdByUrl(link);

	if(tmpHosterId < 0 || tmpHosterId >= hosterList.size()) return -1;

	//gesamt hoster download limit
	if(hosterList.at(tmpHosterId)->maxDownloads > 0 && hosterList.at(tmpHosterId)->free.downloads + hosterList.at(tmpHosterId)->premium.downloads >= hosterList.at(tmpHosterId)->maxDownloads) return -1;

	//wenn max downloader zahl erreicht abbruch, sonst inc downloads
	if(hosterList.at(tmpHosterId)->mode == xmlFileLoader::MODE_FREE)
	{
		if(hosterList.at(tmpHosterId)->free.maxDownloads > 0 && hosterList.at(tmpHosterId)->free.maxDownloads > 0 && hosterList.at(tmpHosterId)->free.downloads >= hosterList.at(tmpHosterId)->free.maxDownloads)
			return -1;
		else
			++hosterList.at(tmpHosterId)->free.downloads;
	} else
	{
		if(hosterList.at(tmpHosterId)->premium.maxDownloads > 0 && hosterList.at(tmpHosterId)->premium.maxDownloads > 0 && hosterList.at(tmpHosterId)->premium.downloads >= hosterList.at(tmpHosterId)->premium.maxDownloads)
			return -1;
		else
			++hosterList.at(tmpHosterId)->premium.downloads;
	}

	int id = getNewFileLoader();

	if(fileLoader.contains(id))
	{
		fileLoader.value(id)->loadXml(hosterList.at(tmpHosterId)->fileName);
		fileLoader.value(id)->setId(id);
		fileLoader.value(id)->setMode(hosterList.at(tmpHosterId)->mode);

		connect(fileLoader.value(id), SIGNAL(downloadFinished(const int &, const bool &)), this, SLOT(slot_xmlFileLoader_downloadFinished(const int &, const bool &)));
		connect(fileLoader.value(id), SIGNAL(statusMsg(const int &, const QString &)), this, SLOT(slot_xmlFileLoader_statusMsg(const int &, const QString &)));
		connect(fileLoader.value(id), SIGNAL(changeMode(const int &, const xmlFileLoader::E_MODE)), this, SLOT(slot_xmlFileLoader_changeMode(const int &, const xmlFileLoader::E_MODE)));

		if(fileLoader.value(id)->setLink(QUrl(link)))
		{
			fileLoader.value(id)->setFolder(folder);
			fileLoader.value(id)->setFile(file);
			fileLoader.value(id)->setLogId(logId);
			fileLoader.value(id)->start();

			writeFileLog(logId, tr("Download started."));

			return id;
		} else
		{
			writeFileLog(logId, tr("Download Link not valid."));
			deleteFileLoader(id);
			return -1;
		}
	} else
	{
		writeFileLog(logId, tr("No free slot available."));
		return -1;
	}
}

int Raptor::getNewFileLoader()
{
	int tmpId = 0;
	while(fileLoader.contains(tmpId))
	{
		++tmpId;
	}

	fileLoader.insert(tmpId, new xmlFileLoader);

	return tmpId;
}

int Raptor::getHosterIdByUrl(const QString &url)
{
	QUrl tmpUrl = QUrl(url);

	for(int i=0; i<hosterList.count(); ++i)
	{
		if(hosterList.at(i)->regexp.indexIn(tmpUrl.host()) != -1) return i;
	}

	return -1;
}

void Raptor::slot_openFolder()
{
	QStringList arguments;
	arguments << "openURL" << ui.labelLocalFolder->text();
	QProcess *fileBrowser = new QProcess(this);
	fileBrowser->start("kfmclient", arguments);
}

void Raptor::addWhenReady(const QString &folder, const QString &url)
{
    if(ready)
        addUrl(folder, url);
    else
        waitingDls.insert(url, folder);
}

bool Raptor::addUrl(const QString &folder, const QUrl &url, const int &state, const uint downloaded, const uint size)
{
	if(url.isValid())
	{
		int tmpId = getHosterIdByUrl(url.toString());

		if(tmpId >= 0)
		{
			int pos = url.toString().lastIndexOf(QDir::separator()) + 1;

			logStrings.append(new QStringList());

			writeFileLog(logStrings.count()-1, tr("Download added."));

			modelDownloads->addDownload(hosterList.at(tmpId)->host, folder, url.toString().mid(pos), url.toString(), logStrings.count()-1, state, downloaded, size);

			if(downloaded == 0 && size == 0) startGetSizeFileLoader(url.toString(), logStrings.count()-1);

			if(!silentAddDl) addInfo(tr("URL: %1 added.").arg(url.toString()));

			dlChanged();

			return true;
		} else
		{
			return false;
		}
	} else
	{
		return false;
	}
}

bool Raptor::addUrl(const QString &folder, const QString &url, const int &state, const uint downloaded, const uint size)
{
	return addUrl(folder, QUrl(url), state, downloaded, size);
}

void Raptor::loadDls()
{
	dontSaveDl = true;
	silentAddDl = true;

	QFile file(folders.raptor.absolutePath() + QDir::separator() + "downloads.xml");

	if(!file.open(QIODevice::ReadOnly)) return;
	QDomDocument doc("Downloads");
	doc.setContent(&file);
	file.close();

	QDomNode tmpDownloads = doc.elementsByTagName("Downloads").at(0);
	QDomNodeList tmpHoster = tmpDownloads.childNodes();

	for(int i=0; i<tmpHoster.size(); ++i)
	{
		QString tmpHosterName = tmpHoster.at(i).attributes().namedItem("name").nodeValue();
		QDomNodeList tmpFolder = tmpHoster.at(i).childNodes();
		QPair<QStandardItem *, QStandardItem *> folder;

		for(int o=0; o<tmpFolder.size(); ++o)
		{
			QString tmpFolderName = tmpFolder.at(o).attributes().namedItem("name").nodeValue();
			folder = modelDownloads->addFolder(tmpHosterName, tmpFolderName);

			QDomNodeList tmpLink = tmpFolder.at(o).childNodes();

			for(int p=0; p<tmpLink.size(); ++p)
			{
				QString tmpLinkName = tmpLink.at(p).attributes().namedItem("url").nodeValue();
				int tmpState = tmpLink.at(p).attributes().namedItem("state").nodeValue().toInt();
				uint tmpDownloaded = tmpLink.at(p).attributes().namedItem("downloaded").nodeValue().toUInt();
				uint tmpSize = tmpLink.at(p).attributes().namedItem("size").nodeValue().toUInt();

				addUrl(tmpFolderName, tmpLinkName, tmpState, tmpDownloaded, tmpSize);
			}

			if(tmpFolder.at(o).attributes().namedItem("expanded").nodeValue() == "1")
			{
			    ui.treeViewDownloads->expand(folder.second->index());
			}
		}

		if(tmpFolder.size() > 0 && tmpHoster.at(i).attributes().namedItem("expanded").nodeValue() == "1")
		{
		    ui.treeViewDownloads->expand(folder.first->index());
		}
	}

	QDomNodeList tmpHistory = doc.elementsByTagName("History").at(0).childNodes();

	for(int i=0; i<tmpHistory.size(); ++i)
	{
		addFinishedDownload(tmpHistory.at(i).attributes().namedItem("file").nodeValue(), tmpHistory.at(i).attributes().namedItem("url").nodeValue(), tmpHistory.at(i).attributes().namedItem("size").nodeValue().toUInt());
	}

	dontSaveDl = false;
	silentAddDl = false;
}

void Raptor::dlChanged()
{
	if(!dontSaveDl) saveDls();
}

void Raptor::saveDls()
{
	QFile file(folders.raptor.absolutePath() + QDir::separator() + "downloads.xml");

	if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
	{
		addInfo(tr("Could not save downloads."));
		return;
	}

	QDomDocument doc("Raptor");
	QDomElement tmpList = doc.createElement("Lists");

	QTextStream out(&file);
	QString folderName = "";

	QDomElement tmpDownloads = doc.createElement("Downloads");

	for(int p=0; p<modelDownloads->rowCount(); ++p)
	{
		QStandardItem *hoster = modelDownloads->item(p);

		QDomElement tmpHoster = doc.createElement("hoster");
		tmpHoster.setAttribute("name", modelDownloads->item(p, FDownloadModel::CD_FILENAME)->text());
		tmpHoster.setAttribute("expanded", ui.treeViewDownloads->isExpanded(hoster->index()));

		if(hoster->hasChildren())
		{
			for(int i=0; i<hoster->rowCount(); ++i)
			{
				QStandardItem *folder = hoster->child(i);

				QDomElement tmpFolder = doc.createElement("folder");
				tmpFolder.setAttribute("name", hoster->child(i, FDownloadModel::CD_FILENAME)->text());
				tmpFolder.setAttribute("expanded", ui.treeViewDownloads->isExpanded(hoster->child(i, FDownloadModel::CD_FILENAME)->index()));

				folderName = hoster->child(i, FDownloadModel::CD_FILENAME)->text();
				if(folder->hasChildren())
				{
					for(int o=0; o<folder->rowCount(); ++o)
					{
						QDomElement tmpLink = doc.createElement("link");

						int tmpInt = folder->child(o, FDownloadModel::CD_HIDDEN_STATE)->text().toInt();
						if(tmpInt == xmlFileLoader::STATE_RUNNING || tmpInt == xmlFileLoader::STATE_DOWNLOADING || tmpInt == xmlFileLoader::STATE_WAITING) tmpInt = xmlFileLoader::STATE_STALLED;

						QPair<quint64, quint64> tmpSize = getSizeFromString(folder->child(o, FDownloadModel::CD_SIZE)->text());

						tmpLink.setAttribute("url", folder->child(o, FDownloadModel::CD_LINK)->text());
						tmpLink.setAttribute("state", QString("%1").arg(tmpInt));
						tmpLink.setAttribute("downloaded", QString("%1").arg(tmpSize.first));
						tmpLink.setAttribute("size", QString("%1").arg(tmpSize.second));

						tmpFolder.appendChild(tmpLink);
					}
				}
				tmpHoster.appendChild(tmpFolder);
			}
		}
		tmpDownloads.appendChild(tmpHoster);
	}
	tmpList.appendChild(tmpDownloads);

	QDomElement tmpHistory = doc.createElement("History");

	for(int i=modelHistory->rowCount()-1; i>=0; --i)
	{
		QDomElement tmpLink = doc.createElement("link");

		tmpLink.setAttribute("file", modelHistory->item(i, 0)->text());
		tmpLink.setAttribute("url", modelHistory->item(i, 1)->text());
		tmpLink.setAttribute("size", modelHistory->item(i, 3)->text());

		tmpHistory.appendChild(tmpLink);
	}

	tmpList.appendChild(tmpHistory);

	doc.appendChild(tmpList);
	doc.save(out, QDomNode::EncodingFromTextStream);
	file.close();

	addInfo(tr("Downloads saved."));
}

void Raptor::reloadSettings()
{
    QSettings settings("raptor-loader", "Raptor");

    QString folderRaptor = settings.value("folderRaptor", QDir::currentPath()).toString();
    QString folderDownload = settings.value("folderDownload", QDir::currentPath() + QDir::separator() + "downloads").toString();
    folders.setDirs(folderRaptor, folderDownload);

    maxDownloads = settings.value("maxDownloads", 1).toInt();

    setDownloadCollumsWidth(settings.value("gui/downloads").toString());

    proxy.host = settings.value("proxy/host", "").toString();
    proxy.port = settings.value("proxy/port", 0).toUInt();
    proxy.type = (QNetworkProxy::ProxyType) settings.value("proxy/type", QNetworkProxy::NoProxy).toInt();
    proxy.user = settings.value("proxy/user", "").toString();
    proxy.pass = settings.value("proxy/pass", "").toString();

    setProxy();

    loadHosterXml();
}

int Raptor::getDownloadCount()
{
	int tmpCout = 0;

	for(int i=0; i<hosterList.size(); ++i)
	{
		tmpCout += hosterList.at(i)->free.downloads;
		tmpCout += hosterList.at(i)->premium.downloads;
	}

	return tmpCout;
}
//





//////////////////GUI

QPixmap Raptor::getPixmapByState(const int &state)
{
	switch(state)
	{
		default:
		case xmlFileLoader::STATE_HISTORY:
			return QPixmap(":/toolbar/file.svg");

		case xmlFileLoader::STATE_ERROR:
			return QPixmap(":/toolbar/file.svg");

		case xmlFileLoader::STATE_STOPPED:
			return QPixmap(":/toolbar/pause.svg");

		case xmlFileLoader::STATE_DOWNLOADING:
		case xmlFileLoader::STATE_RUNNING:
			return QPixmap(":/toolbar/play.svg");

		case xmlFileLoader::STATE_WAITING:
			return QPixmap(":/toolbar/play_waiting.svg");

		case xmlFileLoader::STATE_STALLED:
			return QPixmap(":/toolbar/waiting.svg");

		case xmlFileLoader::STATE_FINISHED:
			return QPixmap(":/toolbar/finished.svg");
	}
}

QString Raptor::getFirstSelectedHosterName()
{
	QItemSelectionModel *selections = ui.treeViewDownloads->selectionModel();
	QModelIndexList selected = selections->selectedRows();

	for(int p=0; p<selected.count(); ++p)
	{
		if(selected.at(p).parent().row() == -1) //ist hoster
		{
			return modelDownloads->item(selected.at(p).row(), FDownloadModel::CD_FILENAME)->text();
		}
	}

	return tr("unknown");
}

QString Raptor::getFirstSelectedFolderName()
{
	QItemSelectionModel *selections = ui.treeViewDownloads->selectionModel();
	QModelIndexList selected = selections->selectedRows();

	for(int p=0; p<selected.count(); ++p)
	{
		if(selected.at(p).parent().row() != -1) //ist kein hoster
		{
			if(selected.at(p).parent().parent().row() == -1) //ist folder
			{
				QStandardItem * hoster = modelDownloads->item(selected.at(p).parent().row());
				return hoster->child(selected.at(p).row(), FDownloadModel::CD_FILENAME)->text();
			}
		}
	}

	return tr("New Folder");
}
//////////////////////////


//////////////////////////private
QMap<QString, bool> Raptor::getAllLinksFromText(QString const& text)
{
    QMap<QString, bool> tmpList;

    /*QRegExp urlRx("(?:http://(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\."
                  ")*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)"
                  "){3}))(?::(?:\d+))?)(?:/(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F"
                  "\d]{2}))|[;:@&=])*)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{"
                  "2}))|[;:@&=])*))*)(?:\?(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{"
                  "2}))|[;:@&=])*))?)?)|(?:ftp://(?:(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?"
                  ":%[a-fA-F\d]{2}))|[;?&=])*)(?::(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-"
                  "fA-F\d]{2}))|[;?&=])*))?@)?(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-"
                  ")*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?"
                  ":\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))?))(?:/(?:(?:(?:(?:[a-zA-Z\d$\-_.+!"
                  "*'(),]|(?:%[a-fA-F\d]{2}))|[?:@&=])*)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'()"
                  ",]|(?:%[a-fA-F\d]{2}))|[?:@&=])*))*)(?:;type=[AIDaid])?)?)|(?:news:(?:"
                  "(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[;/?:&=])+@(?:(?:("
                  "?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:["
                  "a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)){3})))|(?:[a-zA-Z]("
                  "?:[a-zA-Z\d]|[_.+-])*)|\*))|(?:nntp://(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:["
                  "a-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d"
                  "])?))|(?:(?:\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))?)/(?:[a-zA-Z](?:[a-zA-Z"
                  "\d]|[_.+-])*)(?:/(?:\d+))?)|(?:telnet://(?:(?:(?:(?:(?:[a-zA-Z\d$\-_.+"
                  "!*'(),]|(?:%[a-fA-F\d]{2}))|[;?&=])*)(?::(?:(?:(?:[a-zA-Z\d$\-_.+!*'()"
                  ",]|(?:%[a-fA-F\d]{2}))|[;?&=])*))?@)?(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a"
                  "-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d]"
                  ")?))|(?:(?:\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))?))/?)|(?:gopher://(?:(?:"
                  "(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:"
                  "(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)){3}))(?::(?:\d+"
                  "))?)(?:/(?:[a-zA-Z\d$\-_.+!*'(),;/?:@&=]|(?:%[a-fA-F\d]{2}))(?:(?:(?:["
                  "a-zA-Z\d$\-_.+!*'(),;/?:@&=]|(?:%[a-fA-F\d]{2}))*)(?:%09(?:(?:(?:[a-zA"
                  "-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[;:@&=])*)(?:%09(?:(?:[a-zA-Z\d$"
                  "\-_.+!*'(),;/?:@&=]|(?:%[a-fA-F\d]{2}))*))?)?)?)?)|(?:wais://(?:(?:(?:"
                  "(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:"
                  "[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))?"
                  ")/(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))*)(?:(?:/(?:(?:[a-zA"
                  "-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))*)/(?:(?:[a-zA-Z\d$\-_.+!*'(),]|("
                  "?:%[a-fA-F\d]{2}))*))|\?(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]"
                  "{2}))|[;:@&=])*))?)|(?:mailto:(?:(?:[a-zA-Z\d$\-_.+!*'(),;/?:@&=]|(?:%"
                  "[a-fA-F\d]{2}))+))|(?:file://(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]"
                  "|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:"
                  "(?:\d+)(?:\.(?:\d+)){3}))|localhost)?/(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'()"
                  ",]|(?:%[a-fA-F\d]{2}))|[?:@&=])*)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|("
                  "?:%[a-fA-F\d]{2}))|[?:@&=])*))*))|(?:prospero://(?:(?:(?:(?:(?:[a-zA-Z"
                  "\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)"
                  "*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))?)/(?:(?:(?:(?"
                  ":[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[?:@&=])*)(?:/(?:(?:(?:[a-"
                  "zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[?:@&=])*))*)(?:(?:;(?:(?:(?:["
                  "a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[?:@&])*)=(?:(?:(?:[a-zA-Z\d"
                  "$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[?:@&])*)))*)|(?:ldap://(?:(?:(?:(?:"
                  "(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:"
                  "[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))?"
                  "))?/(?:(?:(?:(?:(?:(?:(?:[a-zA-Z\d]|%(?:3\d|[46][a-fA-F\d]|[57][Aa\d])"
                  ")|(?:%20))+|(?:OID|oid)\.(?:(?:\d+)(?:\.(?:\d+))*))(?:(?:%0[Aa])?(?:%2"
                  "0)*)=(?:(?:%0[Aa])?(?:%20)*))?(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F"
                  "\d]{2}))*))(?:(?:(?:%0[Aa])?(?:%20)*)\+(?:(?:%0[Aa])?(?:%20)*)(?:(?:(?"
                  ":(?:(?:[a-zA-Z\d]|%(?:3\d|[46][a-fA-F\d]|[57][Aa\d]))|(?:%20))+|(?:OID"
                  "|oid)\.(?:(?:\d+)(?:\.(?:\d+))*))(?:(?:%0[Aa])?(?:%20)*)=(?:(?:%0[Aa])"
                  "?(?:%20)*))?(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))*)))*)(?:("
                  "?:(?:(?:%0[Aa])?(?:%20)*)(?:[;,])(?:(?:%0[Aa])?(?:%20)*))(?:(?:(?:(?:("
                  "?:(?:[a-zA-Z\d]|%(?:3\d|[46][a-fA-F\d]|[57][Aa\d]))|(?:%20))+|(?:OID|o"
                  "id)\.(?:(?:\d+)(?:\.(?:\d+))*))(?:(?:%0[Aa])?(?:%20)*)=(?:(?:%0[Aa])?("
                  "?:%20)*))?(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))*))(?:(?:(?:"
                  "%0[Aa])?(?:%20)*)\+(?:(?:%0[Aa])?(?:%20)*)(?:(?:(?:(?:(?:[a-zA-Z\d]|%("
                  "?:3\d|[46][a-fA-F\d]|[57][Aa\d]))|(?:%20))+|(?:OID|oid)\.(?:(?:\d+)(?:"
                  "\.(?:\d+))*))(?:(?:%0[Aa])?(?:%20)*)=(?:(?:%0[Aa])?(?:%20)*))?(?:(?:[a"
                  "-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))*)))*))*(?:(?:(?:%0[Aa])?(?:%2"
                  "0)*)(?:[;,])(?:(?:%0[Aa])?(?:%20)*))?)(?:\?(?:(?:(?:(?:[a-zA-Z\d$\-_.+"
                  "!*'(),]|(?:%[a-fA-F\d]{2}))+)(?:,(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-f"
                  "A-F\d]{2}))+))*)?)(?:\?(?:base|one|sub)(?:\?(?:((?:[a-zA-Z\d$\-_.+!*'("
                  "),;/?:@&=]|(?:%[a-fA-F\d]{2}))+)))?)?)?)|(?:(?:z39\.50[rs])://(?:(?:(?"
                  ":(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?"
                  ":[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))"
                  "?)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))+)(?:\+(?:(?:"
                  "[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))+))*(?:\?(?:(?:[a-zA-Z\d$\-_"
                  ".+!*'(),]|(?:%[a-fA-F\d]{2}))+))?)?(?:;esn=(?:(?:[a-zA-Z\d$\-_.+!*'(),"
                  "]|(?:%[a-fA-F\d]{2}))+))?(?:;rs=(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA"
                  "-F\d]{2}))+)(?:\+(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))+))*)"
                  "?))|(?:cid:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[;?:@&="
                  "])*))|(?:mid:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[;?:@"
                  "&=])*)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[;?:@&=]"
                  ")*))?)|(?:vemmi://(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z"
                  "\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\"
                  ".(?:\d+)){3}))(?::(?:\d+))?)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a"
                  "-fA-F\d]{2}))|[/?:@&=])*)(?:(?:;(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a"
                  "-fA-F\d]{2}))|[/?:@&])*)=(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d"
                  "]{2}))|[/?:@&])*))*))?)|(?:imap://(?:(?:(?:(?:(?:(?:(?:[a-zA-Z\d$\-_.+"
                  "!*'(),]|(?:%[a-fA-F\d]{2}))|[&=~])+)(?:(?:;[Aa][Uu][Tt][Hh]=(?:\*|(?:("
                  "?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[&=~])+))))?)|(?:(?:;["
                  "Aa][Uu][Tt][Hh]=(?:\*|(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2"
                  "}))|[&=~])+)))(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|["
                  "&=~])+))?))@)?(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])"
                  "?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:"
                  "\d+)){3}))(?::(?:\d+))?))/(?:(?:(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:"
                  "%[a-fA-F\d]{2}))|[&=~:@/])+)?;[Tt][Yy][Pp][Ee]=(?:[Ll](?:[Ii][Ss][Tt]|"
                  "[Ss][Uu][Bb])))|(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))"
                  "|[&=~:@/])+)(?:\?(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|["
                  "&=~:@/])+))?(?:(?:;[Uu][Ii][Dd][Vv][Aa][Ll][Ii][Dd][Ii][Tt][Yy]=(?:[1-"
                  "9]\d*)))?)|(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[&=~"
                  ":@/])+)(?:(?:;[Uu][Ii][Dd][Vv][Aa][Ll][Ii][Dd][Ii][Tt][Yy]=(?:[1-9]\d*"
                  ")))?(?:/;[Uu][Ii][Dd]=(?:[1-9]\d*))(?:(?:/;[Ss][Ee][Cc][Tt][Ii][Oo][Nn"
                  "]=(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{2}))|[&=~:@/])+)))?))"
                  ")?)|(?:nfs:(?:(?://(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-"
                  "Z\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:"
                  "\.(?:\d+)){3}))(?::(?:\d+))?)(?:(?:/(?:(?:(?:(?:(?:[a-zA-Z\d\$\-_.!~*'"
                  "(),])|(?:%[a-fA-F\d]{2})|[:@&=+])*)(?:/(?:(?:(?:[a-zA-Z\d\$\-_.!~*'(),"
                  "])|(?:%[a-fA-F\d]{2})|[:@&=+])*))*)?)))?)|(?:/(?:(?:(?:(?:(?:[a-zA-Z\d"
                  "\$\-_.!~*'(),])|(?:%[a-fA-F\d]{2})|[:@&=+])*)(?:/(?:(?:(?:[a-zA-Z\d\$\"
                  "-_.!~*'(),])|(?:%[a-fA-F\d]{2})|[:@&=+])*))*)?))|(?:(?:(?:(?:(?:[a-zA-"
                  "Z\d\$\-_.!~*'(),])|(?:%[a-fA-F\d]{2})|[:@&=+])*)(?:/(?:(?:(?:[a-zA-Z\d"
                  "\$\-_.!~*'(),])|(?:%[a-fA-F\d]{2})|[:@&=+])*))*)?)))");*/

    //QRegExp urlRx("(?:https?://)?(?:(?:(?:(?:(?:(?:[a-zA-Z\\d](?:(?:[a-zA-Z\\d]|-)*[a-zA-Z\\d])?)\\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\\d]|-)*[a-zA-Z\\d])?))|(?:(?:\\d+)(?:\\.(?:\\d+)){3}))(?::(?:\\d+))?)(?:/(?:(?:(?:(?:[a-zA-Z\\d$\\-_.+!*'(),]|(?:%[a-fA-F\\d]{2}))|[;:@&=])*)(?:/(?:(?:(?:[a-zA-Z\\d$\\-_.+!*'(),]|(?:%[a-fA-F\\d]{2}))|[;:@&=])*))*)(?:\?(?:(?:(?:[a-zA-Z\\d$\\-_.+!*'(),]|(?:%[a-fA-F\\d]{2}))|[;:@&=])*))?)?)");
    QRegExp urlRx("((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+[\\w\\d:#@%/;$()~_?\\+-=\\\\.&]*)");

    QStringList urls;

    int pos = 0;
    while((pos = urlRx.indexIn(text, pos)) != -1)
    {
        urls.append(urlRx.capturedTexts().at(0).trimmed());
        //qDebug() << "found" << urlRx.capturedTexts().at(0).trimmed();

        pos += urlRx.matchedLength();
    }

    for(int i=0; i<hosterList.count(); ++i)
    {
        QRegExp rx(hosterList.at(i)->regexp);
        QRegExp rx2(hosterList.at(i)->regexp2);

        for(int o=0; o<urls.size(); ++o)
        {
            QUrl tmpUrl(urls.at(o));

            if(tmpUrl.isValid() && (rx.indexIn(tmpUrl.host()) != -1 || hosterList.at(i)->allowOtherHostnames))
            {
//                qDebug() << tmpUrl << rx2.indexIn(urls.at(o)) << rx2.pattern();

                if(rx2.indexIn(urls.at(o)) != -1)
                    tmpList.insert(urls.at(o).trimmed(), true);
            }
        }
    }

    QList<QPair<QPair<QRegExp, bool>, QRegExp> > rxList = urlContainer.getRexExpList();
    for(int i=0; i<rxList.size(); ++i)
    {
        for(int o=0; o<urls.size(); ++o)
        {
            QUrl tmpUrl(urls.at(o));

            if(tmpUrl.isValid() && (rxList.at(i).first.first.indexIn(tmpUrl.host()) != -1 || rxList.at(i).first.second))
                if(rxList.at(i).second.indexIn(urls.at(o)) != -1)
                    tmpList.insert(urls.at(o).trimmed(), false);
        }
    }

    return tmpList;
}
////////////////////////////


///////////////////////SLOTS

void Raptor::slot_clipboard_dataChanged()
{
    if(clipboardDlg)
    {

        if(clipboardDlg->isHidden())
            clipboardDlg->setFolder(getFirstSelectedFolderName());
    } else
    {
        clipboardDlg = new clipboardDialog(this, getFirstSelectedFolderName());
	clipboardDlg->clipboardLinks = &clipboardLinks;
    }

    if(clipboard)
    {
        if(!clipboard->text().isEmpty())
        {
            QMap<QString, bool> tmpList = getAllLinksFromText(clipboard->text());
            QMap<QString, bool>::const_iterator it = tmpList.constBegin();

            while(it != tmpList.constEnd())
            {
                clipboardLinks.insert(it.key(), qMakePair(Qt::Checked, it.value()));
                ++it;
            }
        }
    }

    clipboardDlg->syncLinks();
    if(clipboardLinks.size() > 0) clipboardDlg->show();
}

void Raptor::slot_app_aboutToQuit()
{
    QSettings settings("raptor-loader", "Raptor");

    settings.setValue("gui/geometry", saveGeometry());// fenstergroesse und position speichern
    settings.setValue("gui/state", saveState(1)); // Toolbarstatus speichern

    settings.setValue("gui/downloads", getDownloadCollumsWidth()); //download groesse speichern
    settings.setValue("gui/history", getHistoryCollumsWidth()); //history groesse speichern

    settings.setValue("folderRaptor", folders.raptor.absolutePath());
    settings.setValue("folderDownload", folders.download.absolutePath());

    saveDls();
}

void Raptor::slot_appShow()
{
	if(this->isHidden()) this->show();
}

void Raptor::slot_appHide()
{
	if(!this->isHidden()) this->hide();
}

void Raptor::slot_systemTray_activated(QSystemTrayIcon::ActivationReason reason)
{
	if(reason == QSystemTrayIcon::Trigger)
	{
		if(this->isHidden())
			this->show();
		else
			this->hide();
	}
}

void Raptor::slot_performClose()
{
	QMap<int, QPointer<xmlFileLoader> >::const_iterator i = fileLoader.constBegin();
	while(i != fileLoader.constEnd())
	{
		i.value()->stop();
		deleteFileLoader(i.key());

		++i;
	}

	QCoreApplication::exit(0);
}

//slots xmlFileLoader

void Raptor::slot_xmlFileLoader_changeMode(const int &id, const xmlFileLoader::E_MODE mode)
{
	if(fileLoader.contains(id))
	{
		int tmpHosterId = getHosterIdByUrl(fileLoader.value(id)->link());

		if(tmpHosterId >= 0)
		{
			hosterList.at(tmpHosterId)->mode = mode;
			addInfo(tr("use Free Account for hoster: ") + hosterList.at(tmpHosterId)->host);
		}
	}

}

void Raptor::slot_xmlFileLoader_statusMsg(const int &logId, const QString &text)
{
	writeFileLog(logId, text);
}

void Raptor::slot_xmlFileLoader_loginFinished(const int id, const bool error)
{
	emit hosterLoginFinished(error);

	deleteFileLoader(id);
}

void Raptor::slot_xmlFileLoader_getSizeFinished(const int &id, const bool &error)
{
	if(fileLoader.contains(id))
	{
		if(error)
		{
			setSize(fileLoader.value(id)->logId(), 0, 0);
		} else
		{
			setSize(fileLoader.value(id)->logId(), 0, fileLoader.value(id)->fileSize());
		}
	}

	deleteFileLoader(id);
}

void Raptor::slot_xmlFileLoader_downloadFinished(const int &id, const bool &error)
{
	bool found = false;
	int hosterId = -1;

	if(fileLoader.contains(id))
	{
		//download abschliessen
		for(int i=0; i<modelDownloads->rowCount(); ++i)
		{
			QStandardItem *hoster = modelDownloads->item(i);

			for(int o=0; o<hoster->rowCount(); ++o)
			{
				QStandardItem *folder = hoster->child(o);

				for(int p=0; p<folder->rowCount(); ++p)
				{
					int tmpInt = folder->child(p, FDownloadModel::CD_HIDDEN_DLID)->text().toInt();
					int tmpLogId = folder->child(p, FDownloadModel::CD_HIDDEN_ID)->text().toInt();

					if(tmpInt == id)
					{
						if(error)
						{
							folder->child(p, FDownloadModel::CD_PROGRESS)->setText(QString("0"));
							folder->child(p, FDownloadModel::CD_HIDDEN_STATE)->setText(QString("%1").arg(xmlFileLoader::STATE_ERROR));

							writeFileLog(tmpLogId, tr("Error: ") + fileLoader.value(id)->errorStr());
						} else
						{
							addFinishedDownload(folder->child(p, FDownloadModel::CD_FILENAME)->text(), folder->child(p, FDownloadModel::CD_LINK)->text(), fileLoader.value(id)->fileSize());

							folder->child(p, FDownloadModel::CD_PROGRESS)->setText(QString("100"));
							folder->child(p, FDownloadModel::CD_HIDDEN_STATE)->setText(QString("%1").arg(xmlFileLoader::STATE_FINISHED));
							writeFileLog(tmpLogId, tr("Download finished"));
						}

						folder->child(p, FDownloadModel::CD_HIDDEN_DLID)->setText(QString("-1"));
						folder->child(p, FDownloadModel::CD_SPEED)->setText("-");
						folder->child(p, FDownloadModel::CD_SIZE)->setText(getSizeString(fileLoader.value(id)->fileSize(), fileLoader.value(id)->fileSize()));

						deleteFileLoader(id);

						hosterId = i;
						found = true;
						break;
					}
				}
			}

			if(found) break;
		}

		if(!found)
		{
			deleteFileLoader(id);
			return;
		}

		//naechsten wartenden download starten, nur vom selben hoster !!
		if(hosterId < modelDownloads->rowCount() && hosterId >= 0)
		{
			for(int o=0; o<modelDownloads->item(hosterId)->rowCount(); ++o) //alle folder vom selben hoster
			{
				QStandardItem *folder =  modelDownloads->item(hosterId)->child(o);

				for(int i=0; i<folder->rowCount(); ++i) //links
				{
					int tmpId = folder->child(i, FDownloadModel::CD_HIDDEN_DLID)->text().toInt();
					int tmpState = folder->child(i, FDownloadModel::CD_HIDDEN_STATE)->text().toInt();

					if(tmpId == -1 && tmpState == xmlFileLoader::STATE_STALLED)
					{
                                                int id = startFileLoader(folder->child(i, FDownloadModel::CD_LINK)->text(),
                                                                        folders.download.absolutePath() + QDir::separator() + folder->parent()->child(folder->row(), FDownloadModel::CD_FILENAME)->text(),
                                                                        folder->child(i, FDownloadModel::CD_FILENAME)->text(),
                                                                        folder->child(i, FDownloadModel::CD_HIDDEN_ID)->text().toInt());

						if(id >= 0)
						{
							folder->child(i, FDownloadModel::CD_HIDDEN_DLID)->setText(QString("%1").arg(id));
							folder->child(i, FDownloadModel::CD_HIDDEN_STATE)->setText(QString("%1").arg(xmlFileLoader::STATE_RUNNING));

							addInfo(tr("Download started."));
							return;
						}
					}
				}
			}
		}

		addInfo(tr("Could not start a new download."));
	} else
	{
		addInfo(tr("Something really bad just happened."));
	}
}
//

//gui slots
void Raptor::on_actionAddFolder_triggered()
{
    bool ok;
    QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"), tr("Folder:"), QLineEdit::Normal, tr("New Folder"), &ok);

    text = text.trimmed();

    if(ok && !text.isEmpty())
    {
    	modelDownloads->addFolder(getFirstSelectedHosterName(), text);
    }
}

void Raptor::on_actionAddLink_triggered()
{
    bool ok;
    QString text = QInputDialog::getText(this, tr("Enter Url"), tr("URL:"), QLineEdit::Normal, "", &ok);

    text = text.trimmed();

    if(ok && !text.isEmpty())
    {
    	QUrl tmpUrl = QUrl(text);

    	if(tmpUrl.isValid())
    	{
    		tmpFolderName = getFirstSelectedFolderName();

    		if(!urlContainerIsOpen && urlContainer.loadXmlForLink(tmpUrl.toString()))
    		{
    			urlContainerIsOpen = true;

                                captchaWizard wizard(&urlContainer, tmpUrl, tmpFolderName);
				if(wizard.exec())
				{
                                        tmpFolderName = wizard.folder;

					dontSaveDl = true; //erst dl liste speichern, wenn alle links geladen wurden

					for(int i=0; i<wizard.urlList.count(); ++i)
						addUrl(tmpFolderName, QUrl(wizard.urlList.at(i)));

					dontSaveDl = false;
					dlChanged();
				} else
				{
					QFile::remove(wizard.captcha);
				}

				urlContainerIsOpen = false;
    		} else
    		{
    			addUrl(tmpFolderName, tmpUrl);
    		}
    	}
    }
}

void Raptor::on_treeViewDownloads_clicked(const QModelIndex & index)
{
	ui.textEditLog->clear();
	activeLog = -1;

	if(index.parent().row() == -1) //hoster
	{
		ui.labelSourceUrl->setText("");
		ui.labelLocalFolder->setText("");
	} else
	{
		if(index.parent().parent().row() == -1) //folder
		{
			ui.labelSourceUrl->setText("");
                        ui.labelLocalFolder->setText(folders.download.absolutePath() + QDir::separator() + modelDownloads->itemFromIndex(index)->parent()->child(index.row(), FDownloadModel::CD_FILENAME)->text());
		} else //link
		{
			ui.labelSourceUrl->setText(modelDownloads->itemFromIndex(index)->parent()->child(index.row(), FDownloadModel::CD_LINK)->text());
                        ui.labelLocalFolder->setText(folders.download.absolutePath() + QDir::separator() + modelDownloads->itemFromIndex(index)->parent()->parent()->child(index.parent().row(), FDownloadModel::CD_FILENAME)->text());

			int id = modelDownloads->itemFromIndex(index)->parent()->child(index.row(), FDownloadModel::CD_HIDDEN_ID)->text().toInt();

			activeLog = id;

			for(int i=0; i<logStrings.at(id)->count(); ++i)
			{
				ui.textEditLog->append(logStrings.at(id)->at(i));
			}
		}
	}
}

void Raptor::on_treeViewDownloads_customContextMenuRequested(const QPoint & point)
{
	//ui.menuDownload
	if(downloadRightClickMenu) downloadRightClickMenu->exec(ui.treeViewDownloads->viewport()->mapToGlobal(point));
}

void Raptor::on_treeViewHistory_customContextMenuRequested(const QPoint & point)
{
	//ui.menuHistory
	if(historyRightClickMenu) historyRightClickMenu->exec(ui.treeViewHistory->viewport()->mapToGlobal(point));
}

void Raptor::on_actionMoveUp_triggered()
{
	if(ui.tabWidget->currentIndex() == 0)
	{
		QItemSelectionModel *selections = ui.treeViewDownloads->selectionModel();
		QModelIndexList selected = selections->selectedRows();

		QMap<int, int> rowsHoster;
		QMap<int, int> rowsFolder;
		QMap<int, int> rowsDownload;

		selections->clear();

		for(int i=0; i<selected.count(); ++i)
		{
			if(selected.at(i).parent().row() == -1) //hoster
			{
				rowsHoster.insert(selected.at(i).row(), 0);
			} else
			{
				if(selected.at(i).parent().parent().row() == -1) //folder
				{
					rowsFolder.insert(selected.at(i).row(), selected.at(i).parent().row());
				} else //download
				{
					QStandardItem * hoster = modelDownloads->item(selected.at(i).parent().parent().row());
					QStandardItem * folder = hoster->child(selected.at(i).parent().row());

					if(selected.at(i).row() > 0)
					{
						bool expanded = ui.treeViewDownloads->isExpanded(folder->child(selected.at(i).row())->index());
						QList<QStandardItem *> tmpRow = folder->takeRow(selected.at(i).row());

						folder->insertRow(selected.at(i).row()-1, tmpRow);
						if(expanded) ui.treeViewDownloads->expand(folder->child(selected.at(i).row()-1)->index());
						selections->select(folder->child(selected.at(i).row()-1)->index(), QItemSelectionModel::Select | QItemSelectionModel::Rows);
					}
				}
			}
		}

		QMapIterator<int, int> r(rowsFolder);//folders
		r.toFront();
		while(r.hasNext())
		{
			r.next();

			if(r.key() > 0)
			{
				bool expanded = ui.treeViewDownloads->isExpanded(modelDownloads->item(r.value())->child(r.key())->index());
				QList<QStandardItem *> tmpRow = modelDownloads->item(r.value())->takeRow(r.key());

				modelDownloads->item(r.value())->insertRow(r.key()-1, tmpRow);
				if(expanded) ui.treeViewDownloads->expand(modelDownloads->item(r.value())->child(r.key()-1)->index());
				selections->select(modelDownloads->item(r.value())->child(r.key()-1)->index(), QItemSelectionModel::Select | QItemSelectionModel::Rows);
			}
		}

		QMapIterator<int, int> r2(rowsHoster);//hoster
		r2.toFront();
		while(r2.hasNext())
		{
			r2.next();

			if(r2.key() > 0)
			{
				bool expanded = ui.treeViewDownloads->isExpanded(modelDownloads->item(r2.key())->index());
				QList<QStandardItem *> tmpRow = modelDownloads->takeRow(r2.key());

				modelDownloads->insertRow(r2.key()-1, tmpRow);
				if(expanded) ui.treeViewDownloads->expand(modelDownloads->item(r2.key()-1)->index());
				selections->select(modelDownloads->item(r2.key()-1)->index(), QItemSelectionModel::Select | QItemSelectionModel::Rows);
			}
		}
	}
}

void Raptor::on_actionMoveDown_triggered()
{
	if(ui.tabWidget->currentIndex() == 0)
	{
		QItemSelectionModel *selections = ui.treeViewDownloads->selectionModel();
		QModelIndexList selected = selections->selectedRows();

		QMap<int, int> rowsHoster;
		QMap<int, int> rowsFolder;

		selections->clear();

		for(int i=0; i<selected.count(); ++i)
		{
			if(selected.at(i).parent().row() == -1) //hoster
			{
				rowsHoster.insert(selected.at(i).row(), 0);
			} else
			{
				if(selected.at(i).parent().parent().row() == -1) //folder
				{
					rowsFolder.insert(selected.at(i).row(), selected.at(i).parent().row());
				} else //download
				{
					QStandardItem * hoster = modelDownloads->item(selected.at(i).parent().parent().row());
					QStandardItem * folder = hoster->child(selected.at(i).parent().row());

					if(selected.at(i).row() < folder->rowCount() - 1)
					{
						bool expanded = ui.treeViewDownloads->isExpanded(folder->child(selected.at(i).row())->index());
						QList<QStandardItem *> tmpRow = folder->takeRow(selected.at(i).row());

						folder->insertRow(selected.at(i).row()+1, tmpRow);
						if(expanded) ui.treeViewDownloads->expand(folder->child(selected.at(i).row()+1)->index());
						selections->select(folder->child(selected.at(i).row()+1)->index(), QItemSelectionModel::Select | QItemSelectionModel::Rows);
					}
				}
			}
		}

		QMapIterator<int, int> r(rowsFolder);//folder
		r.toBack();
		while(r.hasPrevious())
		{
			r.previous();

			if(r.key() < modelDownloads->item(r.value())->rowCount() - 1)
			{
				bool expanded = ui.treeViewDownloads->isExpanded(modelDownloads->item(r.value())->child(r.key())->index());
				QList<QStandardItem *> tmpRow = modelDownloads->item(r.value())->takeRow(r.key());

				modelDownloads->item(r.value())->insertRow(r.key()+1, tmpRow);
				if(expanded) ui.treeViewDownloads->expand(modelDownloads->item(r.value())->child(r.key()+1)->index());
				selections->select(modelDownloads->item(r.value())->child(r.key()+1)->index(), QItemSelectionModel::Select | QItemSelectionModel::Rows);
			}
		}

		QMapIterator<int, int> r2(rowsHoster);//hoster
		r2.toBack();
		while(r2.hasPrevious())
		{
			r2.previous();

			if(r2.key() < modelDownloads->rowCount() - 1)
			{
				bool expanded = ui.treeViewDownloads->isExpanded(modelDownloads->item(r2.key())->index());
				QList<QStandardItem *> tmpRow = modelDownloads->takeRow(r2.key());

				modelDownloads->insertRow(r2.key()+1, tmpRow);
				if(expanded) ui.treeViewDownloads->expand(modelDownloads->item(r2.key()+1)->index());
				selections->select(modelDownloads->item(r2.key()+1)->index(), QItemSelectionModel::Select | QItemSelectionModel::Rows);
			}
		}
	}
}

void Raptor::on_actionDelete_triggered()
{
	dontSaveDl = true;

	if(ui.tabWidget->currentIndex() == 0)
	{
		int deleteInt = 0;

		QItemSelectionModel *selections = ui.treeViewDownloads->selectionModel();
		QModelIndexList selected = selections->selectedRows();

		QMap<int, int> rowsHoster;
		QMap<int, int> rowsFolder;
		QList< QMap<int, int> *> rowsDownload;

		for(int i=0; i<selected.count(); ++i)
		{
			if(selected.at(i).parent().row() == -1) //hoster
			{
				rowsHoster.insert(selected.at(i).row(), 0);
			} else if(selected.at(i).parent().parent().row() == -1) //folder
			{
				rowsFolder.insert(selected.at(i).row(), selected.at(i).parent().row());
			} else
			{
				int hoster = selected.at(i).parent().parent().row();

				while(rowsDownload.count() <= hoster)
					rowsDownload.append(new QMap<int, int>);

				rowsDownload.at(hoster)->insert(selected.at(i).row(), selected.at(i).parent().row());
			}
		}

		selections->clear();

		for(int i=0; i<rowsDownload.count(); ++i)
		{
			QMapIterator<int, int> r(*rowsDownload.at(i));
			r.toBack();
			while(r.hasPrevious())
			{
				r.previous();

				deleteDownload(modelDownloads->item(i)->child(r.value()), r.key());
				++deleteInt;
			}

			delete rowsDownload.at(i);
		}

		QMapIterator<int, int> r2(rowsFolder);//folder
		r2.toBack();
		while(r2.hasPrevious())
		{
			r2.previous();

			if(modelDownloads->item(r2.value())->child(r2.key())->hasChildren())
			{
				deleteInt += modelDownloads->item(r2.value())->child(r2.key())->rowCount();

				for(int i=modelDownloads->item(r2.value())->child(r2.key())->rowCount()-1; i>=0; --i)
				{
					deleteDownload(modelDownloads->item(r2.value())->child(r2.key()), i);
				}
			}

			modelDownloads->item(r2.value())->removeRow(r2.key()); //folder loeschen
		}

		QMapIterator<int, int> r3(rowsHoster);//hoster
		r3.toBack();
		while(r3.hasPrevious())
		{
			r3.previous();

			if(modelDownloads->item(r3.key())->hasChildren())
			{
				for(int i=0; i<modelDownloads->item(r3.key())->rowCount(); ++i) //folders
				{
					if(modelDownloads->item(r3.key())->child(i)->hasChildren())
					{
						for(int o=modelDownloads->item(r3.key())->child(i)->rowCount()-1; o>=0; --o) //dl
						{
							deleteDownload(modelDownloads->item(r3.key())->child(i), o);
						}

						deleteInt += modelDownloads->item(r3.key())->child(i)->rowCount();
					}
				}
			}

			modelDownloads->removeRow(r3.key()); //hoster loeschen
		}

		if(deleteInt > 0) addInfo(QString(tr("%1 link(s) deleted.")).arg(deleteInt));
	} else
	{
		QItemSelectionModel *selections = ui.treeViewHistory->selectionModel();
		QModelIndexList selected = selections->selectedRows();

		QMap<int, int> rowsDownload;

		for(int i=0; i<selected.count(); ++i)
		{
			rowsDownload.insert(selected.at(i).row(), selected.at(i).row());
		}

		selections->clear();

		QMapIterator<int, int> r(rowsDownload);
		r.toBack();
		while(r.hasPrevious())
		{
			r.previous();

			modelHistory->removeRow(r.value());
		}
	}

	dontSaveDl = false;
	dlChanged();
}

void Raptor::on_actionStart_triggered()
{
	if(ui.tabWidget->currentIndex() == 0)
	{
		modifyItems(ACTION_START);
	}
}

void Raptor::on_actionPause_triggered()
{
	if(ui.tabWidget->currentIndex() == 0)
	{
		modifyItems(ACTION_PAUSE);
	}
}

void Raptor::on_actionRemoveFinished_triggered()
{
    if(ui.tabWidget->currentIndex() == 0)
    {
	QList< QMap<int, int> > rowsDownload;

	for(int p=0; p<modelDownloads->rowCount(); ++p)
	{
		QMap<int, int> mapDownloads;

		QStandardItem *hoster = modelDownloads->item(p);

		if(hoster->hasChildren())
		{
			for(int i=0; i<hoster->rowCount(); ++i)
			{
				QStandardItem *folder = hoster->child(i);

				if(folder->hasChildren())
				{
					for(int o=0; o<folder->rowCount(); ++o)
					{
						if(folder->child(o, FDownloadModel::CD_HIDDEN_STATE)->text().toInt() == xmlFileLoader::STATE_FINISHED)
						{
							mapDownloads.insert(o, i);
						}
					}
				}
			}
		}

		rowsDownload.append(mapDownloads);
	}

	dontSaveDl = true;

	for(int i=0; i<rowsDownload.count(); ++i)
	{
		QMapIterator<int, int> r(rowsDownload.at(i));
		r.toBack();
		while(r.hasPrevious())
		{
			r.previous();
			deleteDownload(modelDownloads->item(i)->child(r.value()), r.key());
		}
	}

	dontSaveDl = false;
	saveDls();
    }
}

void Raptor::on_actionAddFile_triggered()
{
	importWizard wizard;
	tmpFolderName = getFirstSelectedFolderName();

	if(wizard.exec())
	{
		dontSaveDl = true; //erst dl liste speichern, wenn alle links geladen wurden

		for(int i=0; i<wizard.urlList.count(); ++i)
			addUrl(tmpFolderName, QUrl(wizard.urlList.at(i)));

		dontSaveDl = false;
		dlChanged();
	}
}

void Raptor::on_actionPreferences_triggered()
{
	configDialog config(this);
	if(config.exec())
	{

	}

	reloadSettings();
}

void Raptor::slot_timerFileList_timeout()
{
	for(int p=0; p<modelDownloads->rowCount(); ++p)
	{
		QStandardItem *hoster = modelDownloads->item(p);

		if(hoster->hasChildren())
		{
			for(int i=0; i<hoster->rowCount(); ++i)
			{
				QStandardItem *folder = hoster->child(i);

				if(folder->hasChildren())
				{
					//int progress = 0;
					double speed = 0;
					quint64 folderSize = 0;
					quint64 folderDownloaded = 0;

					for(int o=0; o<folder->rowCount(); ++o)
					{
						int tmpId = folder->child(o, FDownloadModel::CD_HIDDEN_DLID)->text().toInt();

						if(tmpId >= 0)
						{
							S_INFOS tmpInfos;
							if(getLoaderInfos(tmpId, tmpInfos))
							{
								//if(tmpInfos.state != xmlFileLoader::STATE_WAITING) progress += tmpInfos.progress;
								speed += tmpInfos.speed;
								folderDownloaded += tmpInfos.downloaded;
								folderSize += tmpInfos.fileSize;

								folder->child(o)->setIcon(getPixmapByState(tmpInfos.state));

								folder->child(o, FDownloadModel::CD_PROGRESS)->setText(QString("%1").arg(tmpInfos.progress));
								folder->child(o, FDownloadModel::CD_TIMELEFT)->setText(getTimeString(tmpInfos.timeLeft));

								folder->child(o, FDownloadModel::CD_ELAPSED)->setText(getTimeString((int)((double)tmpInfos.downloadStart.time().elapsed() / 1000)));

								folder->child(o, FDownloadModel::CD_SPEED)->setText(getSpeedString(tmpInfos.speed));
								folder->child(o, FDownloadModel::CD_SIZE)->setText(getSizeString(tmpInfos.downloaded, tmpInfos.fileSize));
							}
						} else
						{
							folder->child(o)->setIcon(getPixmapByState(folder->child(o, FDownloadModel::CD_HIDDEN_STATE)->text().toInt()));

							//progress += folder->child(o, FDownloadModel::CD_PROGRESS)->text().toInt();

							QPair<quint64, quint64> tmpSize = getSizeFromString(folder->child(o, FDownloadModel::CD_SIZE)->text());
							folderDownloaded += tmpSize.first;
							folderSize += tmpSize.second;

							//fortschritt soll erhalten bleiben -> nicht auf 0 setzen
							folder->child(o, FDownloadModel::CD_TIMELEFT)->setText(QString("-"));
							folder->child(o, FDownloadModel::CD_ELAPSED)->setText(QString("-"));
						}
					}

					//hoster->child(i, FDownloadModel::CD_PROGRESS)->setText(QString("%1").arg((int)(progress / folder->rowCount())));
					int progress = 0;
					if(folderSize > 0 && folderSize >= folderDownloaded)	progress = (int)((100*folderDownloaded) / folderSize);

					hoster->child(i, FDownloadModel::CD_PROGRESS)->setText(QString("%1").arg(progress));
					hoster->child(i, FDownloadModel::CD_SPEED)->setText(getSpeedString(speed));
					hoster->child(i, FDownloadModel::CD_SIZE)->setText(getSizeString(folderDownloaded, folderSize));

					if(speed > 0)
					{
						hoster->child(i, FDownloadModel::CD_TIMELEFT)->setText(getTimeString((int)((folderSize - folderDownloaded) / speed)));
					} else
					{
						hoster->child(i, FDownloadModel::CD_TIMELEFT)->setText("-");
					}
				} else
				{
					hoster->child(i, FDownloadModel::CD_SIZE)->setText(getSizeString(0));
					hoster->child(i, FDownloadModel::CD_PROGRESS)->setText("0");
				}
			}
		}
	}
}
//


////public

void Raptor::setDownloadCollumsWidth(const QString &width)
{
	QStringList tmpStrList = width.split("|");

	for(int i=0; i<tmpStrList.size(); ++i)
	{
		if(tmpStrList.at(i).toInt() > 0) ui.treeViewDownloads->setColumnWidth(i, tmpStrList.at(i).toInt());
	}
}

QString Raptor::getDownloadCollumsWidth()
{
	QStringList tmpStrList = QStringList();

	int i = 0;
	while(ui.treeViewDownloads->columnWidth(i) > 0 || ui.treeViewDownloads->isColumnHidden(i))
	{
		tmpStrList.append(QString("%1").arg(ui.treeViewDownloads->columnWidth(i)));
		++i;
	}

	return tmpStrList.join("|");
}

void Raptor::setHistoryCollumsWidth(const QString &width)
{
	QStringList tmpStrList = width.split("|");

	for(int i=0; i<tmpStrList.size(); ++i)
	{
		if(tmpStrList.at(i).toInt() > 0) ui.treeViewHistory->setColumnWidth(i, tmpStrList.at(i).toInt());
	}
}

QString Raptor::getHistoryCollumsWidth()
{
	QStringList tmpStrList = QStringList();

	int i = 0;
	while(ui.treeViewHistory->columnWidth(i) > 0 || ui.treeViewHistory->isColumnHidden(i))
	{
		tmpStrList.append(QString("%1").arg(ui.treeViewHistory->columnWidth(i)));
		++i;
	}

	return tmpStrList.join("|");
}

void Raptor::doHosterLogin(const QString hoster, const QString user, const QString pass)
{
	if(startLoginFileLoader(hoster, user, pass) < 0) emit hosterLoginFinished(true);
}
//

//public slots
void Raptor::handleMessage(const QString& message)
{
	if(message.trimmed() == "") return;

	if(addUrl("dbus", message))
		qDebug() << QString(tr("Url (\"%1\") added !!")).arg(message);
	else
		qDebug() << QString(tr("Url (\"%1\") ist fehlerhaft !!")).arg(message);
}
//
